package com.aleyn.router.inject.instance

import com.aleyn.router.inject.Core
import com.aleyn.router.inject.getFullName
import com.aleyn.router.inject.qualifier.Qualifier
import kotlin.reflect.KClass

/**
 * @author: Aleyn
 * @date: 2023/7/27 11:21
 *
 * 定义了依赖注入中使用的核心数据结构和类型。
 */

/**
 * 实例的种类，用于区分单例和工厂模式。
 */
enum class Kind {
    SINGLETON, // 单例模式，全局只有一个实例
    FACTORY    // 工厂模式，每次请求都创建一个新实例
}

/**
 * 依赖定义的元数据。
 *
 * @param T 实例的类型。
 * @param primaryType 实例的主要类型 (KClass)。
 * @param qualifier 可选的限定符，用于区分同一类型的不同实例。
 * @param def 创建实例的 lambda 表达式。
 * @param kind 实例的种类 (SINGLETON 或 FACTORY)。
 */
data class Definition<T>(
    val primaryType: KClass<*>,
    var qualifier: Qualifier? = null,
    val def: Def<T>,
    val kind: Kind,
)

/**
 * 为给定的类型和限定符生成一个唯一的映射键。
 * 这个键用于在实例注册表中存储和检索实例工厂。
 *
 * @param clazz 实例的 KClass。
 * @param typeQualifier 可选的限定符。
 * @return 生成的唯一字符串键。
 */
fun mappingKey(clazz: KClass<*>, typeQualifier: Qualifier?): String {
    val tq = typeQualifier?.value ?: ""
    return "${clazz.getFullName()}:$tq"
}

/**
 * 定义一个用于创建实例的 lambda 表达式的类型别名。
 * 它是一个扩展函数，接收 [Parameters] 作为参数，并返回类型为 `T` 的实例。
 */
typealias Def<T> = Core.(Parameters) -> T

/**
 * 创建一个 [Definition] 实例的辅助函数。
 *
 * @param T 要创建定义的实例类型。
 * @param kind 实例的种类。
 * @param qualifier 可选的限定符。
 * @param definition 创建实例的 lambda 表达式。
 * @return 创建的 [Definition] 实例。
 */
inline fun <reified T> createDefinition(
    kind: Kind = Kind.SINGLETON,
    qualifier: Qualifier? = null,
    noinline definition: Def<T>,
) = Definition(
    T::class,
    qualifier,
    definition,
    kind
)